package pers.fengxu.learnmybatis.proxy;

import pers.fengxu.learnmybatis.config.Configure;
import pers.fengxu.learnmybatis.db.DbUtil;
import pers.fengxu.learnmybatis.demo.entity.User;
import pers.fengxu.learnmybatis.jdbc.MapperStatement;
import pers.fengxu.learnmybatis.type.TypeHandler;
import pers.fengxu.learnmybatis.util.CommUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

public class MapperProxy implements InvocationHandler {
    private Configure configure;

    public MapperProxy(Configure configure) {
        this.configure = configure;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String id = method.getDeclaringClass().getPackageName() + "." + method.getName();
        MapperStatement mapperStatement = configure.getMapperStatementMap().get(id);
        Connection conn = DbUtil.getConn();
        PreparedStatement stmt = conn.prepareStatement(mapperStatement.getSql());
        ResultSet resultSet = stmt.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        Class<?> resultType = User.class;
        List<User> resultList = new ArrayList<>();
        while (resultSet.next()) {
            Object resultObject = resultType.getConstructor().newInstance();
            for (int i = 0; i < columnCount; i++) {
                String columnName = metaData.getColumnName(i + 1);
                String value = resultSet.getString(columnName);
                String fieldName = CommUtil.toSmallCamelCase(columnName);
                Field field = resultType.getDeclaredField(fieldName);
                Method declaredMethod = resultType.getDeclaredMethod("set" + CommUtil.toBigCamelCase(columnName), field.getType());
                declaredMethod.invoke(resultObject, TypeHandler.convertValue(field.getType(), value));
            }
            resultList.add((User) resultObject);
        }
        return resultList;
    }
}
